package com.liangxy.zhyl.base;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import com.github.pagehelper.Page;
import com.liangxy.zhyl.utils.ConvertHandler;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.*;

import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;

/**
 * 分页结果包装类 - 统一封装分页查询结果
 * 泛型T表示数据列表中元素的类型
 * @author itheima
 */
@Data
@ApiModel(value = "分页数据消息体", description = "分页数据统一对象")
@Builder
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@NoArgsConstructor
public class PageResponse<T> {

    @ApiModelProperty(value = "总条目数", required = true) // Swagger属性描述
    private Long total = 0L; // 总记录数，默认0

    @ApiModelProperty(value = "页尺寸", required = true)
    private Integer pageSize = 0; // 每页大小，默认0

    @ApiModelProperty(value = "总页数", required = true)
    private Long pages = 0L; // 总页数，默认0

    @ApiModelProperty(value = "页码", required = true)
    private Integer page = 0; // 当前页码，默认0

    @ApiModelProperty(value = "数据列表", required = true)
    private List<T> records = Collections.EMPTY_LIST; // 当前页数据列表，默认为空列表

    /**
     * 通过MyBatis分页对象构造PageResponse(不处理数据列表)
     * @param page MyBatis分页对象
     */
    public PageResponse(Page<?> page) {
        this.page = Convert.toInt(page.getPageNum()); // 当前页码
        this.total = page.getTotal(); // 总记录数
        this.pageSize = Convert.toInt(page.getPageSize()); // 每页大小
        this.pages = (long) page.getPages(); // 总页数
    }

    /**
     * 通过MyBatis分页对象构造PageResponse(设计上要处理数据列表，但实际未实现)
     * @param page MyBatis分页对象
     * @param clazz 目标数据类型Class对象
     * @deprecated 此方法有bug，未处理records字段
     */
    public PageResponse(Page<?> page, Class<T> clazz) {
        this(page); // 调用上一个构造方法
        // 注意：这里应该处理records字段但没有处理
    }

    /**
     * 创建一个空的PageResponse实例
     * @return 空的分页响应对象
     */
    public static <T> PageResponse<T> getInstance() {
        return PageResponse.<T>builder().build(); // 使用建造者模式创建
    }

    /**
     * 将MyBatis分页对象转换为PageResponse(不处理数据列表)
     * @param page 源分页对象
     * @return 分页响应对象
     */
    public static <T> PageResponse<T> of(Page<?> page) {
        return PageResponse.<T>builder()
                .page(Convert.toInt(page.getPageNum())) // 设置页码
                .pageSize(Convert.toInt(page.getPageSize())) // 设置页大小
                .pages((long) page.getPages()) // 设置总页数
                .total(page.getTotal()) // 设置总记录数
                .build();
    }

    /**
     * 将MyBatis分页对象转换为PageResponse(自动转换数据列表类型)
     * @param page 源分页对象
     * @param clazz 目标数据类型Class对象
     * @return 分页响应对象
     */
    public static <T> PageResponse<T> of(Page<?> page, Class<T> clazz) {
        return of(page, clazz, null); // 调用下面的方法，convertHandler传null -- 浅拷贝
    }

    /**
     * 将MyBatis分页对象转换为PageResponse(支持自定义数据转换)
     * @param page 源分页对象
     * @param clazz 目标数据类型Class对象
     * @param convertHandler 自定义转换处理器
     * @return 分页响应对象
     */
    public static <O, T> PageResponse<T> of(Page<O> page, Class<T> clazz, ConvertHandler<O, T> convertHandler) {
        return PageResponse.<T>builder()
                .page(Convert.toInt(page.getPageNum()))
                .pageSize(Convert.toInt(page.getPageSize()))
                .pages((long) page.getPages())
                .total(page.getTotal())
                .records(copyToList(page.getResult(), clazz, convertHandler)) // 转换数据列表
                .build();
    }

    /**
     * 转换已有PageResponse的数据类型(自动转换)
     * @param origin 源分页响应对象
     * @param clazz 目标数据类型Class对象
     * @return 新类型的分页响应对象
     */
    public static <O, T> PageResponse<T> of(PageResponse<O> origin, Class<T> clazz) {
        return of(origin, clazz, null); // 调用下面的方法，convertHandler传null
    }

    /**
     * 转换已有PageResponse的数据类型(支持自定义转换)
     * @param origin 源分页响应对象
     * @param clazz 目标数据类型Class对象
     * @param convertHandler 自定义转换处理器
     * @return 新类型的分页响应对象
     */
    public static <O, T> PageResponse<T> of(PageResponse<O> origin, Class<T> clazz, ConvertHandler<O, T> convertHandler) {
        // 创建新实例并复制除records外的属性
        PageResponse<T> target = PageResponse.getInstance();
        BeanUtil.copyProperties(origin, target, "records");

        // 如果源数据为空，直接返回
        if (CollUtil.isEmpty(origin.getRecords())) {
            return target;
        }

        // 转换数据列表
        List<T> targetList = copyToList(origin.getRecords(), clazz, convertHandler);
        target.setRecords(targetList);

        return target;
    }

    /**
     * 从List创建分页响应对象(可指定完整分页信息)
     * @param items 数据列表
     * @param page 当前页码(可选)
     * @param pageSize 每页大小(可选)
     * @param pages 总页数(可选)
     * @param counts 总记录数(可选)
     * @return 分页响应对象
     */
    public static <T> PageResponse<T> of(List<T> items, Integer page, Integer pageSize, Long pages, Long counts) {
        // 创建分页响应对象并设置分页信息(使用Optional处理null值)
        PageResponse<T> pageResponse = PageResponse.<T>builder()
                .page(Optional.ofNullable(page).orElse(1)) // 页码默认为1
                .pageSize(Optional.ofNullable(pageSize).orElse(1)) // 页大小默认为1
                .pages(Optional.ofNullable(pages).orElse(1L)) // 总页数默认为1
                .total(Optional.ofNullable(counts).orElse(1L)) // 总记录数默认为1
                .build();

        // 如果数据列表不为空，设置数据
        if (CollUtil.isEmpty(items)) {
            return pageResponse;
        }

        pageResponse.setRecords(items);
        return pageResponse;
    }

    /**
     * 从List创建分页响应对象(使用默认分页信息)
     * @param items 数据列表
     * @return 分页响应对象
     */
    public static <T> PageResponse<T> of(List<T> items) {
        return of(items, null, null, null, null); // 调用上面的方法，所有分页参数传null
    }

    /**
     * 从可变参数创建分页响应对象
     * @param elements 数据元素(可变参数)
     * @return 分页响应对象
     */
    @SafeVarargs
    public static <E> PageResponse<E> of(E... elements) {
        return of(List.of(elements)); // 将可变参数转为List后调用上面的方法
    }

    /**
     * 使用自定义函数转换已有PageResponse的数据
     * @param origin 源分页响应对象
     * @param function 自定义转换函数
     * @return 新类型的分页响应对象
     */
    public static <O, T> PageResponse<T> of(PageResponse<O> origin, Function<List<O>, List<T>> function) {
        List<T> orderVOList = function.apply(origin.getRecords()); // 应用转换函数
        // 使用转换后的列表创建新的分页响应对象
        return PageResponse.of(orderVOList, origin.getPage(), origin.getPageSize(), origin.getPages(), origin.total);
    }

    /**
     * 内部方法：转换数据列表类型
     * @param content 源数据列表
     * @param clazz 目标类型Class对象
     * @param convertHandler 自定义转换处理器
     * @return 转换后的数据列表
     */
    private static <T, O> List<T> copyToList(List<O> content, Class<T> clazz, ConvertHandler<O, T> convertHandler) {
        // 使用Hutool工具进行基本类型转换
        List<T> targetList = BeanUtil.copyToList(content, clazz);

        // 如果有自定义转换处理器，进行额外处理
        if (CollUtil.isNotEmpty(targetList) && ObjectUtil.isNotEmpty(convertHandler)) {
            for (int i = 0; i < content.size(); i++) {
                // 对每个元素应用自定义转换
                convertHandler.map(content.get(i), targetList.get(i));
            }
        }
        return targetList;
    }
}